/* sht10.c

Copyright (C) Alex S. (mailto: md5sum@alexsp.ru)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details
http://www.gnu.org/licenses/gpl-2.0.html.

You should have received a copy of the GNU General Public License
along with this program in the file gpl-2.0.txt;
if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "sht10.h"
#if HUMIDITY==10
#include "usart.h"

#define SHT10_DATA_1() 	{DDRB&=~(1<<5);PORTB|=(1<<5);}
#define SHT10_DATA_0() 	{PORTB&=~(1<<5);DDRB|=(1<<5);}
#define SHT10_SCK_1()	{DDRB&=~(1<<6);PORTB|=(1<<6);}
#define SHT10_SCK_0()	{PORTB&=~(1<<6);DDRB|=(1<<6);}
#define SHT10_SCK_pulse() {SHT10_SCK_1();SHT_nop();SHT10_SCK_0();}
#ifndef SHT_nop
#define SHT_nop() __asm__ __volatile__("nop\r\nnop\r\n")
#endif // SHT_nop
#define SHT10_DATA_RD 	PINB&(1<<5)

int8_t SHT_temp=25;
uint8_t SHT_hum=0;
static uint8_t reverce_crc(uint8_t a);
static uint8_t SHT10_crc(uint8_t crc, const uint8_t val);

void SHT10_start() {
	uint8_t i;

	SHT10_SCK_0();
	SHT10_DATA_1();
	/*Reset communication*/
	for (i=0;i<9;i++){
		SHT10_SCK_1();
		SHT_nop();
		SHT10_SCK_0();
		SHT_nop();
	}
	SHT10_SCK_1();
	SHT_nop();
	SHT10_DATA_0();
	SHT_nop();
	SHT10_SCK_0();
	SHT_nop();
	SHT10_SCK_1();
	SHT_nop();
	SHT10_DATA_1();
	SHT_nop();
	SHT10_SCK_0();
}

void SHT10_reset() {
	uint8_t addr=0b00011110;
	uint8_t i;
	SHT10_start();
	for (i=0;i<8;i++){
		if (addr&0x80) {SHT10_DATA_1()} else {SHT10_DATA_0()};
		SHT10_SCK_pulse();
		addr<<=1;
	}
	SHT10_SCK_pulse();
}


static hw_ret_status SHT10_cmd(const uint8_t cmd){
	uint8_t i;
	uint8_t tmp=cmd;

	SHT10_start();
	for (i=0;i<8;i++){
		if (tmp&0x80) {SHT10_DATA_1()} else {SHT10_DATA_0()};
		SHT10_SCK_pulse();
		tmp<<=1;
	}
	SHT10_SCK_1();
	if (SHT10_DATA_RD) {
#ifdef DBG_SHT
		debug("No ASK in startT\r\n");
#endif
		return ERROR;
	}
	SHT10_SCK_0();
	return SUCCESS;
}

hw_ret_status SHT10_startH() {
	return SHT10_cmd(0b00000101);
}
hw_ret_status SHT10_startT() {
	return SHT10_cmd(0b00000011);
}

hw_ret_status SHT10_get_res(uint16_t * val, uint8_t cmd){
	uint8_t i,j,tmp;
	uint8_t crc=0;
	hw_ret_status err=SUCCESS;

	if (SHT10_DATA_RD) return WAIT;
	tmp=0;
	SHT10_DATA_1();
	for (j=0;j<3;j++) {
		for (i=0;i<8;i++) {
			SHT10_SCK_1();
			tmp<<=1;
			tmp|=((SHT10_DATA_RD)>0?1:0);
			SHT10_SCK_0();
		}
		switch (j) {
		case 0:
			*val=tmp<<8;
			SHT10_DATA_0();
			SHT10_SCK_pulse();
			SHT10_DATA_1();
			crc=SHT10_crc(crc,cmd);
			crc=SHT10_crc(crc,tmp);
			break;
		case 1:
			*val|=tmp;
			SHT10_DATA_0();
			SHT10_SCK_pulse();
			SHT10_DATA_1();
			crc=SHT10_crc(crc,tmp);
			break;
		case 2:
			SHT10_DATA_1();
			SHT10_SCK_pulse();
#ifdef DBG_SHT
			itoa(tmp,debug_str,16);
			debug(debug_str);
			debug(" read crc\r\n");
			itoa(reverce_crc(crc),debug_str,16);
			debug(debug_str);
			debug(" calc crc\r\n");
#endif
			if (tmp!=reverce_crc(crc)) err=CRC;
			break;
		default :
			break;
		}
		tmp=0;
	}

	return err;
}
hw_ret_status SHT10_calc_H(){
	uint16_t soh=0;
	hw_ret_status ret;

	if ((ret=SHT10_get_res(&soh,5))!=SUCCESS) {
#ifdef DBG_SHT
		debug("Error calc H\r\n");
#endif
		return ret;
	}

	SHT_hum=(uint8_t)((double)soh*0.0367-0.0000015955*(double)soh*(double)soh-2.0468);
	SHT_hum+=(SHT_temp-25)*(0.01+0.0008*(double)soh);
#ifdef DBG_SHT
	itoa(soh,debug_str,16);
	debug(debug_str);
	debug(" SOH\r\n");
	itoa(SHT_hum,debug_str,10);
	debug(debug_str);
	debug(" RH\r\n");
#endif
	return SUCCESS;
}
hw_ret_status SHT10_calc_T(){
	uint16_t sot=0;
	hw_ret_status ret;

	if ((ret=SHT10_get_res(&sot,3))!=SUCCESS) {
#ifdef DBG_SHT
		debug("Error calc T\r\n");
#endif
		return ret;
	}
	SHT_temp=(int8_t)(((double)sot/100.0)-40.1);
#ifdef DBG_SHT
	itoa(sot,debug_str,16);
	debug(debug_str);
	debug(" SOT\r\n");
	itoa(SHT_temp,debug_str,10);
	debug(debug_str);
	debug(" T\r\n");
#endif

	return SUCCESS;
}

uint8_t SHT10_humidity() {
	return SHT_hum;
}
int8_t SHT10_temperature() {
	return SHT_temp;
}

uint8_t SHT10_crc(uint8_t crc, const uint8_t val){
	uint8_t i;
	uint8_t tmp=val;

	for (i=0;i<8;i++) {
		if ((crc&0x80)==(tmp&0x80)) {
			crc=crc<<1;
		} else {
			crc=crc<<1;
			crc^=0x31;
		}
		tmp=tmp<<1;
	}
	return crc;
}

uint8_t reverce_crc(const uint8_t a){
	uint8_t i;
	uint8_t b=0;

	for (i=0;i<8;i++) {
		b|=(((a>>i)&0x01)<<(7-i));
	}
	return b;
}

hw_ret_status SHT10_softreset(){
	return SHT10_cmd(0b00011110);
}

#endif //HUMIDITY
